﻿/*
 * alfa_ecu.c
 *
 * Created: 04.02.2013 5:14:07
 *  Author: Артём
 */ 


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include "config.h"
#include "at90can_drv.h"
#include "uart/uart_lib.h"
#include "uart/uart_drv.h"
#include "adc/adc_drv.h"
#include "can/can_lib.h"
#include "rtc/rtc_drv.h"
#include "crc32/crc32.h"
#include "spi/spi_lib.h"
#include "pid/pid.h"
#include "ntctemp/ntctemp.h"
#include "wbo2/wbo2.h"

U16 rtc_milliseconds_stamp_1, rtc_milliseconds_stamp_2, rtc_milliseconds_stamp_3;

typedef struct
{
	U8		buffer[256],
			message_size,
			message,
			count,
			ms2_data_received,
			ms2_data_sended;
}usart_packet;

usart_packet usart0_packet;

U8 usart1_buffer[256];
U8 usart1_message;
U8 usart0_count, usart1_count;
//volatile U8 usart0_ms2_data_received = 1;
//volatile U8 usart0_ms2_data_sended = 0;

U8 ThrottlePidTableSRAM[100];
U8 ThrottlePidTableEEPROM[100] EEMEM =
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0V ...
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF  // ... 5V
};

U16 ECUSettingsSRAM[11];
U16 ECUSettingsEEPROM[11] EEMEM =
{
	0x0000, // ecu_status
	0x0352, // engine_rpm_request_idle_1 = 850 rpm
	0x0384, // engine_rpm_request_idle_2 = 900 rpm
	0x0000, // throttle_accelerator_min_1
	0x0000, // throttle_accelerator_min_2
	0x0000, // throttle_accelerator_max_1
	0x0000, // throttle_accelerator_max_2
	0x0000, // throttle_body_min_1
	0x0000, // throttle_body_max_1
	0x0000, // reserved
	0x0000	// reserved
};

extern void Send_CanImmoMsg(void);
extern void Send_CanEngineStatusMsg(void);
extern void Send_SerialCommandToMS2(void);
extern void CheckFanSpeed(U8 state);
extern void Program_CheckFanSpeed(void);
extern void Program_Send_CanEngineStatusMsg(void);
extern void Program_ThrottleAcceleratorControl(void);
extern void Program_CruiseControlRuntime(void);
extern void InitADCRuntime(void);
extern void InitPidRuntime(void);
extern void LoadSettingsFromEEPROM(void);
extern void SaveSettingsToEEPROM(void);
extern void MS2PacketParse(usart_packet *usart0_packet);

struct ecu_info 
{
	U8		ecu_status,
			ecu_version,
			fan_speed_status,
			cruise_control_status,
			cruise_control_last_speed,
			car_speed;
			
	U16		engine_rpm_request_idle_1,
			engine_rpm_request_idle_2,
			throttle_accelerator_1,
			throttle_accelerator_min_1,
			throttle_accelerator_max_1,
			throttle_accelerator_2,
			throttle_accelerator_min_2,
			throttle_accelerator_max_2,
			throttle_body_1,
			throttle_body_min_1,
			throttle_body_max_1,
			engine_rpm;
	S16		engine_clt;
} ms2;

struct PID_DATA ThrottlePidData;
#define K_P_THTL     5.00
#define K_I_THTL     0.00
#define K_D_THTL     0.00

struct PID_DATA CruiseControlPidData;
#define K_P_CRSC     1.00
#define K_I_CRSC     0.00
#define K_D_CRSC     0.00

void LoadSettingsFromEEPROM(void)
{
	// Uncomment this!
	// eeprom_read_block (( void *) ThrottlePidTableSRAM , ( const void *) ThrottlePidTableEEPROM , sizeof(ThrottlePidTableEEPROM));
	eeprom_read_block (( void *) ECUSettingsSRAM , ( const void *) ECUSettingsEEPROM , sizeof(ECUSettingsEEPROM));
}

void SaveSettingsToEEPROM(void)
{
	eeprom_update_block(( const void *) ThrottlePidTableSRAM , ( void *) ThrottlePidTableEEPROM , sizeof(ThrottlePidTableEEPROM));
}

void Program_CheckFanSpeed(void)
{
	if (rtc_milliseconds-rtc_milliseconds_stamp_1 >= 1000)
	{
		rtc_milliseconds_stamp_1 = rtc_milliseconds;
	    if ( (PINA & (1<<PINA0)) == 0)
	    {
		    CheckFanSpeed(1);
	    }
	    else if( (PINA & (1<<PINA1)) == 0)
	    {
		    CheckFanSpeed(2);
	    }
	    else
	    {
		    CheckFanSpeed(0);
	    }
	}	
}

void InitADCRuntime(void)
{
	adc_init(AVCC_AS_VREF, NO_LEFT_ADJUST, 0);
}

void Program_ThrottleAcceleratorControl(void)
{
	//ms2.engine_rpm = adc_single_conversion(0);
}

void Program_CruiseControlRuntime(void)
{
	
}

void Program_Send_CanEngineStatusMsg(void)
{
	if (rtc_milliseconds-rtc_milliseconds_stamp_2 >= 50)
	{
		rtc_milliseconds_stamp_2 = rtc_milliseconds;
		Send_CanEngineStatusMsg();
	}
}

void Program_Send_SerialCommandToMS2(void)
{
	if ((rtc_milliseconds-rtc_milliseconds_stamp_3 >= 150) && (usart0_packet.ms2_data_received == 1))
	{
		rtc_milliseconds_stamp_3 = rtc_milliseconds;
		Send_SerialCommandToMS2();
		usart0_packet.ms2_data_received = 1; // just for fun
	}
	/*else if ((rtc_milliseconds-rtc_milliseconds_stamp_3 >= 5000) && (usart0_packet.ms2_data_received == 0))
	{
		rtc_milliseconds_stamp_3 = rtc_milliseconds;
		Send_SerialCommandToMS2();		
	}*/
}

void InitPidRuntime(void)
{
	  pid_Init(K_P_THTL * SCALING_FACTOR, K_I_THTL * SCALING_FACTOR , K_D_THTL * SCALING_FACTOR , &ThrottlePidData);
	  pid_Init(K_P_CRSC * SCALING_FACTOR, K_I_CRSC * SCALING_FACTOR , K_D_CRSC * SCALING_FACTOR , &CruiseControlPidData);
};

int main(void)
{
    // Init UARTs
    // Init UART-0 at 9600 bauds
    Uart_select(UART_0);
    uart_init(CONF_8BIT_NOPAR_1STOP, 9600);
	
	// Init UART-1 at 115200 bauds
	Uart_select(UART_1);
	uart_init(CONF_8BIT_NOPAR_1STOP, 115200);
	
	spi_init(SPI_MASTER|SPI_MSB_FIRST|SPI_DATA_MODE_2|SPI_CLKIO_BY_32);
	rtc_int_init();
	can_init(0);
	InitADCRuntime();
	InitPidRuntime();
	LoadSettingsFromEEPROM();
	
	#ifdef WBO2
		WBO2_HeaterInit();
	#endif
	
	Send_CanImmoMsg();
	Send_SerialCommandToMS2();

	//rtc_milliseconds_stamp_1 = rtc_milliseconds;
	//rtc_milliseconds_stamp_2 = rtc_milliseconds;
	
	sei();

	while(1)
    {
		Program_Send_CanEngineStatusMsg();
		Program_CheckFanSpeed();
		Program_ThrottleAcceleratorControl();
		Program_CruiseControlRuntime();
		Program_Send_SerialCommandToMS2();
    }
}

void MS2PacketParse(usart_packet *usart0_packet)
{
	usart0_packet->count = 0;
	usart0_packet->message_size = 0;
	usart0_packet->ms2_data_sended = 0;
	usart0_packet->ms2_data_received = 0;
	
	//ms2.engine_clt = usart0_packet->buffer[25];
	//ms2.engine_clt <<= 8;
	//ms2.engine_clt += usart0_packet->buffer[26];
	
	ms2.engine_rpm = usart0_packet->buffer[9];
	ms2.engine_rpm <<= 8;
	ms2.engine_rpm += usart0_packet->buffer[10];
}

ISR(USART0_RX_vect)
{
	Uart_select(UART_0);
	
	if (usart0_packet.ms2_data_sended == 1 && usart0_packet.count < 2 && usart0_packet.message_size == 0)
	{
		usart0_packet.buffer[usart0_packet.count] = uart_getchar();
		if(usart0_packet.count == 1)
		{
			usart0_packet.message_size = usart0_packet.buffer[0];
			usart0_packet.message_size <<= 8;
			usart0_packet.message_size += usart0_packet.buffer[1];
		}
		usart0_packet.count++;
	}
	else if (usart0_packet.ms2_data_sended == 1 && usart0_packet.count >= 2 && usart0_packet.message_size > 0 && (usart0_packet.count < usart0_packet.message_size + 5 ))
	{
		usart0_packet.buffer[usart0_packet.count] = uart_getchar();
		usart0_packet.count++;
	}
	else if (usart0_packet.ms2_data_sended == 1 && (usart0_packet.count < usart0_packet.message_size + 6 ))
	{
		usart0_packet.buffer[usart0_packet.count] = uart_getchar();
		
		usart0_packet.ms2_data_received = 1;
		usart0_packet.ms2_data_sended = 0;
		MS2PacketParse(&usart0_packet);
	}
	
};

ISR(USART1_RX_vect)
{

};

void CheckFanSpeed(U8 state)
{
	switch (state) {
	case 1:
		PORTA |= (1 << PORTA3);      // turn on PA3
		PORTA &= ~(1 << PORTA4);     // turn off PA4
		ms2.fan_speed_status = 1;
		break;
	case 2:
		PORTA |= (1 << PORTA4);      // turn on PA4
		PORTA &= ~(1 << PORTA3);     // turn off PA3
		ms2.fan_speed_status = 2;
		break;
	default:
		if(ms2.engine_clt < 93)
		{
			PORTA &= ~(1 << PORTA3);     // turn off PA3
			PORTA &= ~(1 << PORTA4);     // turn off PA4
			ms2.fan_speed_status = 0;
		}
		else if(ms2.engine_clt >= 93 && ms2.engine_clt < 100)
		{
			PORTA |= (1 << PORTA3);      // turn on PA3
			PORTA &= ~(1 << PORTA4);     // turn off PA4
			ms2.fan_speed_status = 1;
		}
		else if(ms2.engine_clt >= 100)
		{
			PORTA |= (1 << PORTA4);      // turn on PA4
			PORTA &= ~(1 << PORTA3);     // turn off PA3
			ms2.fan_speed_status = 2;
		}
	}
}

void Send_CanImmoMsg(void)
{
	U8  immo_msg_buffer[7];
	st_cmd_t immo_msg;
	// --- Tx Command
	immo_msg.pt_data = &immo_msg_buffer[0];;
	
	immo_msg_buffer[0] = 0x00;
	immo_msg_buffer[1] = 0x06;
	immo_msg_buffer[2] = 0x00;
	immo_msg_buffer[3] = 0x00;
	immo_msg_buffer[4] = 0x00;
	immo_msg_buffer[5] = 0x00;
	immo_msg_buffer[6] = 0x00;
	
	immo_msg.id.std = 0x041;
	immo_msg.dlc = 7;
	immo_msg.cmd = CMD_TX_DATA;
	immo_msg.ctrl.ide=0;
	
	// --- Enable Tx
	while(can_cmd(&immo_msg) != CAN_CMD_ACCEPTED);
	// --- Wait for Tx completed
	while(can_get_status(&immo_msg) == CAN_STATUS_NOT_COMPLETED);
}

void Send_CanEngineStatusMsg(void)
{
	U8  engine_status_msg_buffer[8];
	st_cmd_t engine_status_msg;
	// --- Tx Command
	engine_status_msg.pt_data = &engine_status_msg_buffer[0];;
	
	engine_status_msg_buffer[0] = 0x00;
	engine_status_msg_buffer[1] = 0x00;
	engine_status_msg_buffer[2] = 0x00;
	engine_status_msg_buffer[3] = ms2.engine_clt + 40;
	engine_status_msg_buffer[4] = 0x00;
	engine_status_msg_buffer[5] = 0x00;
	engine_status_msg_buffer[6] = ms2.engine_rpm / 32;
	engine_status_msg_buffer[7] = 0x00;
	
	engine_status_msg.id.std = 641;
	engine_status_msg.dlc = 8;
	engine_status_msg.cmd = CMD_TX_DATA;
	engine_status_msg.ctrl.ide=0;
	
	// --- Enable Tx
	while(can_cmd(&engine_status_msg) != CAN_CMD_ACCEPTED);
	// --- Wait for Tx completed
	while(can_get_status(&engine_status_msg) == CAN_STATUS_NOT_COMPLETED);
}

//------------------------------------------------------------------------------
//  @fn can_error_mode
//!
//! Exit in UART ECHO MODE if CAN ID == 0 as CAN error simulation.
//!
//! @warning UART's at 38400 bauds
//!
//! @param  none.
//!
//! @return  none
//!
//------------------------------------------------------------------------------


//--- C A N    E R R O R

void can_error_mode(void)
{
	U8 i;
	U8 txt_ech_mod[]="======= UART in ECHO MODE =======";

	Uart_select(UART_0); uart_mini_printf ("\r\n-0- ======= CAN LINE ERROR ");
	
	for(i=0; i<6; i++)
	{
		Uart_select(UART_0); uart_mini_printf ("*");
	}

	Uart_select(UART_0); uart_mini_printf (" Exit From Program! ======= -0-\r\n\n");
	
	//- UART ECHO
	Uart_select(UART_0); uart_mini_printf ("-0 %s 0-\r\n",txt_ech_mod);
	while(1)
	{
		Uart_select(UART_0);
		if (uart_test_hit())
		{
			uart_putchar(uart_getchar());   // Echo on UART-0
		}
	}
}

void Send_SerialCommandToMS2(void)
{
	// MS2 "A" command
	// 00 01 41 D3 D9 9E 8B
	Uart_select(UART_0);
	uart_putchar(0x00);
	uart_putchar(0x01);
	uart_putchar(0x41);
	uart_putchar(0xD3);
	uart_putchar(0xD9);
	uart_putchar(0x9E);
	uart_putchar(0x8B);
	//uart_putchar('\n');
	
	usart0_packet.ms2_data_sended = 1;
	usart0_packet.ms2_data_received = 0;
	
	//uart_mini_printf("A\n");
}